using System;
using System.Collections;
using System.Reflection;

using System.Xml.Serialization;

namespace GURUCORE.Framework.Core.Data
{
	/// <summary>
	/// G: This base class map a database record to a DataObject.    
    /// All  xxxDTO class in GURUCORE pattern must inherit this base class.
	/// </summary>
	[Serializable]
    [System.Diagnostics.DebuggerStepThrough()]
	public abstract class DTOBase
	{
		protected Hashtable m_htIsNull;
		private object m_oDTOTag;
        

		protected Hashtable m_htForceUpdateNull;

		public const string DTOTAG_FLD = "DTOTag";

		/// <summary>
		/// Contain runtime data of DTO, this property is not store in database, and not map any record field.
		/// </summary>
		public object DTOTag
		{
			get
			{
				return m_oDTOTag;
			}
			set
			{
				m_oDTOTag = value;
			}
		}

		public string DTOTagSerializedString
		{
			get
			{
				if (m_oDTOTag != null)
				{
					return m_oDTOTag.ToString();
				}
				else
				{
					return string.Empty;
				}				
			}
			set
			{
				m_oDTOTag = value;
			}
		}

        


		public DTOBase()
		{
			m_htIsNull = new Hashtable();
			m_htForceUpdateNull = new Hashtable();
			//using reflection to set all field to null at creation
			Type tInstance = this.GetType();

			PropertyInfo[] arrProps = tInstance.GetProperties();
			foreach (PropertyInfo oProp in arrProps)
			{
				object[] arrAttributes = oProp.GetCustomAttributes(typeof(PersistencePropertyAttribute),false);
				if (arrAttributes.Length > 0)
				{
					m_htIsNull.Add(((PersistencePropertyAttribute)arrAttributes[0]).FieldName,true);
					m_htForceUpdateNull.Add(((PersistencePropertyAttribute)arrAttributes[0]).FieldName, false);
				}
			}
		}

		/// <summary>
		/// Kiểm tra xem giá trị của trường có null không
		/// </summary>
		/// <param name="p_sFieldName"></param>
		/// <returns></returns>
		public bool IsNull(string p_sFieldName)
		{
			try
			{
				return (bool)m_htIsNull[p_sFieldName];
			}
			catch
			{
				return false;
			}
		}


		/// <summary>
		/// Set this field value to null (null in database)
		/// </summary>
		/// <param name="p_sFieldName"></param>
		public void SetNull(string p_sFieldName)
		{
			m_htIsNull[p_sFieldName] = true;
		}

		public void ForceUpdateNull(string p_sFieldName)
		{
			m_htForceUpdateNull[p_sFieldName] = true;
		}

		public bool IsForceUpdateNull(string p_sFieldName)
		{
			try
			{
				return (bool)m_htForceUpdateNull[p_sFieldName];
			}
			catch
			{
				return false;
			}			
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="p_sFieldName"></param>
		public void SetNotNull(string p_sFieldName)
		{
			// REVIEW: lockevn: consider to remove
			m_htIsNull[p_sFieldName] = false;
		}

		/// <summary>
		/// call IsNull(fieldname) for all field
		/// </summary>
		public void Empty()
		{
			string[] arrKey = new string[m_htIsNull.Keys.Count];
			m_htIsNull.Keys.CopyTo(arrKey, 0);
			foreach (string sKey in arrKey)
			{
				m_htIsNull[sKey] = true;
			}
		}

        
        // GURUCORE: knowledge
        // these 2 functions will be call in DTO child class.
        // the property (in the child class) call these 2 functions MUST be declare at the end of the class. Because remoting ser/deserialization mechanism call the child property first, call the last property first.

		protected string GetIsNullSerializedString()
		{
			string sSerializedString = string.Empty;
			foreach (DictionaryEntry oEntry in m_htIsNull)
			{
				if ((bool)oEntry.Value)
				{
					sSerializedString += "1";
				}
				else
				{
					sSerializedString += "0";
				}
			}
			return sSerializedString;
		}

		protected void SetIsNullSerializedString(string p_sValue)
		{
			Hashtable htNew = new Hashtable();
			int nIdx = 0;
			foreach (DictionaryEntry oEntry in m_htIsNull)
			{
				if (p_sValue[nIdx] == '0')
				{
					htNew.Add(oEntry.Key, false);
				}
				else
				{
					htNew.Add(oEntry.Key, true);
				}
				nIdx++;
			}
			this.m_htIsNull = htNew;
		}


	}	// end class DTO
}	// end namespace
